using System;
//using System.Collections.Generic;
//using System.Text;
//using Microsoft.DirectX;

using Microsoft.DirectX;
namespace Noein.Physics
{
    namespace Collision
    {
        public enum BoundingVolumeType
        {
            Sphere = 1,
            AABB = 2
        }

        public abstract class BoundingVolume
        {
            public abstract BoundingVolumeType GetBVType();
        }

        public class Sphere : BoundingVolume
        {
            private float radius;
            public float Radius
            {
                get { return radius; }
            }

            public Sphere(float radius)
            {
                this.radius = radius;
            }

            public override BoundingVolumeType  GetBVType()
            {
                return BoundingVolumeType.Sphere;
            }
        }

        public class AABB : BoundingVolume
        {
            private Vector3 extents;
            public Vector3 Extents
            {
                get { return extents; }
            }

            public AABB(Vector3 extents)
            {
                this.extents = extents;
            }
            public AABB(float x, float y, float z)
            {
                extents = new Vector3(x, y, z);
            }

            public override BoundingVolumeType GetBVType()
            {
                return BoundingVolumeType.AABB;
            }
        }

        public class Test
        {
            public static bool Sweep(Object a, Object b, ref float u0, ref float u1, ref bool fail)
            {
                bool retval = false;

                Spatial sA = a.Spatial, sB = b.Spatial;

                switch (a.BoundingVolume.GetBVType() & b.BoundingVolume.GetBVType())
                {
                    case BoundingVolumeType.Sphere & BoundingVolumeType.Sphere:
                        #region sphere-sphere sweep test

                        Sphere sphereA = a.BoundingVolume as Sphere, sphereB = b.BoundingVolume as Sphere;
                        Vector3 vA = sA.Position - sA.PreviousPosition;
                        Vector3 vB = sB.Position - sB.PreviousPosition;
                        Vector3 sAB = sB.PreviousPosition - sA.PreviousPosition;
                        Vector3 vAB = vB - vA;
                        float rAB = sphereA.Radius + sphereB.Radius;
                        float _a = vAB.LengthSq();
                        float _b = 2 * Vector3.Dot(vAB, sAB);
                        float _c = sAB.LengthSq() - rAB * rAB;

                        if (retval = _c < 0f)
                        {
                            // currently overlapping
                            u0 = u1 = 0;
                        }
                        else
                        {
                            // compute the numerical solution to the quadratic equation
                            float q = _b * _b - 4f * _a * _c;

                            if (retval = q >= 0f)
                            {
                                float sq = (float)System.Math.Sqrt(q);
                                float d = 1f / (2f * _a);
                                u0 = (-_b + sq) * d;
                                u1 = (-_b - sq) * d;

                                // order solution by size
                                if (u0 > u1) { float u0_old = u0; u0 = u1; u1 = u0_old; }

                                // check if solution is within the valid range [0, 1]
                                retval = (u0 <= 1f) && (u0 >= 0);
                            }
                        }

                        #endregion
                        break;

                    default:
                        fail = true;
                        break;
                    //throw new Exception("Bounding volume type unsupported by the sweep test!");
                }

                return retval;
            }

            public static bool Intersect(Object a, Object b, ref bool fail)
            {
                bool retval = false;

                //Spatial sA = a.Spatial, sB = b.Spatial;

                switch (a.BoundingVolume.GetBVType() & b.BoundingVolume.GetBVType())
                {
                    case BoundingVolumeType.Sphere & BoundingVolumeType.AABB:
                        #region sphere-box inersection test

                        float[] center;
                        float radius;
                        float[] min, max;

                        Sphere sphere;
                        AABB aabb;
                        Spatial sA, sB;
                        if (a.BoundingVolume.GetBVType() == BoundingVolumeType.Sphere)
                        {
                            sphere = (Sphere)a.BoundingVolume;
                            aabb = (AABB)b.BoundingVolume;
                            sA = a.Spatial;
                            sB = b.Spatial;
                        }
                        else
                        {
                            sphere = (Sphere)b.BoundingVolume;
                            aabb = (AABB)a.BoundingVolume;
                            sA = b.Spatial;
                            sB = a.Spatial;
                        }
                        center = new float[] { sA.Position.X, sA.Position.Y, sA.Position.Z };
                        radius = sphere.Radius;
                        Vector3 v = sB.Position - aabb.Extents;
                        min = new float[] { v.X, v.Y, v.Z };
                        v = sB.Position + aabb.Extents;
                        max = new float[] { v.X, v.Y, v.Z };

                        float s, d = 0;
                        for (int i = 0; i < 3; i++)
                        {
                            if (center[i] < min[i])
                            {
                                s = center[i] - min[i];
                                d += s * s;
                            }
                            else if (center[i] > max[i])
                            {
                                s = center[i] - max[i];
                                d += s * s;
                            }
                        }

                        retval = d <= radius * radius;

                        #endregion
                        break;
                    default:
                        fail = true;
                        break;
                    //throw new Exception("Bounding volume type unsupported by the intersect test!");
                }

                return retval;
            }
        }
    }
   

//    //public enum Geometry
//    //{
//    //    CircularCylinder,
//    //    CircularCylindricalShell,
//    //    RectangularCylinder,
//    //    Sphere,
//    //    SphericalShell
//    //}

//    //public class Collision
//    //{
//    //    #region detection only

//    //    public static bool SphereAABBTest(Object target, Object target2)
//    //    {
//    //        bool collided = false;

//    //        // HACK assuming AABB
//    //        Vector3 dimension = new Vector3(target2.PhysicsInfo.Dimensions[0], target2.PhysicsInfo.Dimensions[1], target2.PhysicsInfo.Dimensions[2]);
//    //        Vector3 min = target2.Spatial.Position - dimension * .5f;
//    //        Vector3 max = target2.Spatial.Position + dimension * .5f;
//    //        Vector3 c = target.Spatial.Position;
//    //        float s, d = 0f;
//    //        s = c.X < min.X ? c.X - min.X : c.X - max.X;
//    //        d += s * s;
//    //        s = c.Y < min.Y ? c.Y - min.Y : c.Y - max.Y;
//    //        d += s * s;
//    //        s = c.Z < min.Z ? c.Z - min.Z : c.Z - max.Z;
//    //        d += s * s;
//    //        collided = d <= (target.PhysicsInfo.Dimensions[0] * target.PhysicsInfo.Dimensions[0]);

//    //        if (collided)
//    //        {
//    //            int b = 1;
//    //        }

//    //        return false;
//    //    }


//    //    #endregion

//    //    #region detection and determination

   

//    //    #endregion
//    //}
}
